// 参考： https://threejsfundamentals.org/threejs/lessons/threejs-post-processing.html
import { 
  AmbientLight,
  Color,
  Mesh,
  MeshPhongMaterial,
  PerspectiveCamera,
  Scene, 
  SphereGeometry, 
  SpotLight, 
  TextureLoader, 
  Vector2, 
  WebGLRenderer
} from "three";
import stats from '../utils/stats';
// 调用
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { FilmPass } from 'three/examples/jsm/postprocessing/FilmPass'
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
import { GUI } from "dat.gui";

let scene = new Scene();
let renderer = setRenderer();
let camera = setCamera();

setLight();
let { composer, earth }= init();

const trackballControls = new OrbitControls(camera, renderer.domElement);

render();

function render() {
  stats.update();
  trackballControls.update();

  earth.rotation.y += 0.001;

  requestAnimationFrame(render);
  composer.render();
}


function setRenderer() {
  const renderer = new WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 支持阴影生成 
  renderer.shadowMap.enabled = true;
  document.body.appendChild(renderer.domElement);

  return renderer
}

function setCamera(): PerspectiveCamera {
  let camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(0, 20, 40);
  scene.add( camera );

  return camera;
}

// 灯光设置
function setLight() {
  scene.add(new AmbientLight(0x444444));
  scene.add(new AmbientLight(0x343434));
  
  let spotLight = new SpotLight(0xffffff);
  spotLight.position.set(-10, 30, 40);
  spotLight.shadow.mapSize.width = 2048;
  spotLight.shadow.mapSize.height = 2048;
  spotLight.shadow.camera.fov = 15;
  spotLight.decay =2;
  spotLight.penumbra = 0.05;
  spotLight.castShadow = true;

  scene.add(spotLight);
  // scene.add(new SpotLightHelper(spotLight));
}

/** 功能区 */
function init() {
  let { earth } = addEarth();
  scene.add(earth);

  // 设置效果
  let renderPass = new RenderPass(scene, camera);
  let effectFilm = new FilmPass(0.8, 0.325, 256, 0);
  effectFilm.renderToScreen = true;

  let composer = new EffectComposer(renderer);
  composer.addPass(renderPass);
  composer.addPass(effectFilm);

  addGUI(effectFilm);

  return { composer, earth };
}

function addGUI(obj: FilmPass): void {
  const gui = new GUI();
  let controls = {
    grayScale: false,
    noiseIntensity: 0.8,
    scanlinesIntensity: 0.325,
    scanlinesCount: 256
  }

  gui.add(controls, 'grayScale').onChange(val => {
    (<any>obj.uniforms).grayscale.value = val;
  });
  gui.add(controls, 'noiseIntensity', 0, 1, 0.01).onChange(val => {
    (<any>obj.uniforms).nIntensity.value = val;
  });
  gui.add(controls, 'scanlinesIntensity', 0, 1, 0.01).onChange(val => {
    (<any>obj.uniforms).sIntensity.value = val;
  });
  gui.add(controls, 'scanlinesCount', 0, 500, 1).onChange(val => {
    (<any>obj.uniforms).sCount.value = val;
  });
}

function addEarth(): { earth: Mesh } {
  let loader = new TextureLoader();
  let material = new MeshPhongMaterial({
    map: loader.load('/textures/earth/Earth.png'),
    normalMap: loader.load('/textures/earth/EarthNormal.png'),
    specularMap: loader.load('/textures/earth/EarthSpec.png'),
    specular: new Color(0x4444aa),
    normalScale: new Vector2(6, 6),
    shininess: 0.5
  });
  let earth = new Mesh(
    new SphereGeometry(13, 40, 40),
    material
  );
  
  return {
    earth
  }
}